using System;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Collections;
using SAY.Web.Security.QueryStringManagerModule.Exceptions;

namespace SAY.Web.Security.QueryStringManagerModule
{
    public class QueryStringManager
    {
        #region Singleton class Pattern
        /// <summary>
        /// Singleton private instance
        /// </summary>
        private static QueryStringManager _instance = null;

        /// <summary>
        /// Lock object for thread-safety. (For Lazy Initialization in public instance accessor)
        /// </summary>
        private static readonly object lockObject = new object();

        /// <summary>
        /// Constructor is private
        /// </summary>
        private QueryStringManager()
        {
            this.Pages = new Hashtable();
        } 

        /// <summary>
        /// Public Instance Accessor
        /// </summary>
        public static QueryStringManager Instance
        {
            get
            {
                lock (lockObject)
                {
                    if (_instance == null)
                    {
                        _instance = new QueryStringManager();
                    }
                    return _instance;
                }
            }
        } 
        #endregion

        private static System.Collections.Hashtable _pages;

        private System.Collections.Hashtable Pages
        {
            get { return QueryStringManager._pages; }
            set { QueryStringManager._pages = value; }
        }

        public void RegisterPage(string url, QueryStringProtections protection, EncryptionTypes encryption)
        {
            this.Pages.Add(url, new PageSettings(url, encryption, protection));
        }

        public void RegisterParameter(string pageUrl, QueryStringItem queryStringItem)
        {
            ((PageSettings)this.Pages[pageUrl]).Parameters.Add(queryStringItem.Name, queryStringItem);
        }

        public void CheckQueryString(HttpContext context)
        {
            PageSettings page = this.Pages[context.Request.AppRelativeCurrentExecutionFilePath] as PageSettings;
            
            if (page != null)
            {
                switch (page.Protection)
                {

                    default:
                    case QueryStringProtections.Strict:
                        CheckParameterTypes(context, page);
                        CheckParamaters(context, page);
                        break;
                    case QueryStringProtections.Gentle:
                        CheckParamaters(context, page);
                        break;
                    case QueryStringProtections.Free:
                        break;
                }
            }
        }

        private void CheckParameterTypes(HttpContext context, PageSettings page)
        {
            QueryStringItem parameter;
            for (int i = 0; i < context.Request.QueryString.Count; i++)
            {
                parameter = page.Parameters[context.Request.QueryString.Keys[i]] as QueryStringItem;
                
                try
                {
                    Convert.ChangeType(HttpContext.Current.Request.QueryString[i], parameter.ParameterType);
                }
                catch 
                {
                    throw new ParameterMismatchException(context.Request.QueryString.Keys[i]);
                }
            }
        }

        private void CheckParamaters(HttpContext context, PageSettings page)
        {
            for (int i = 0; i < context.Request.QueryString.Count; i++)
            {
                if (!page.Parameters.Contains(context.Request.QueryString.Keys[i]))
                {
                    throw new ParameterNotRegisteredException(context.Request.QueryString.Keys[i]);
                }
            }
        }
    }
}